import { Button, Divider, Dropdown, Input, Menu, Upload } from "antd"
import { UploadChangeParam, UploadFile } from "antd/lib/upload/interface"
import dayjs from "dayjs"
import { ChangeEventHandler, useCallback, useMemo, useRef, useState } from "react"
import { Helmet } from "react-helmet"
import styled from "styled-components"
import { bzj, mscs, names, subtotalLists } from "./config"
import { readCSV, totalLists } from "./csvParse"
import Draggable from "./Draggable"
import { readXLSX } from "./xlsParse"

// 增加千分位分隔符
function addNumSplit(val?: number | string) {
  if (val) {
    if (typeof val === "string") {
      return parseFloat(val).toFixed(2).replace(".00", "")
    }
    return val.toFixed(2).replace(".00", "") // .replace(/\B(?=(?:\d{3})+\b)/g, ',')
  }
  return "0"
}
enum Encodes {
  gb2312 = "gb2312",
  utf8 = "utf8"
}
enum OperateState {
  idle,
  operate,
  done
}
export type List = {
  key: string;
  vcl: number;
  czsz: number;
  name: string;
}[]

type Union = {
  [propname: string]: {
    vcl: number; // 持仓量
    vcl_positive: number; // 多仓统计
    vcl_negative: number; // 空仓统计
    czsz: number; // 持仓市值
    name: string;
    jsj: number | undefined; // 结算价
    mscs: number; // 每手乘数
    bzj: string; // 保证金
  }
}
function Main() {
  // 统计文件
  const [selectFileList, setSelectFileList] = useState<UploadFile<any>[]>([])
  // 附加文件
  const [addonFile, setAddonFile] = useState<UploadFile<any>[]>([])
  const [fileName, setFileName] = useState(dayjs().format("YYYYMMDD"))
  const [encode, setEncode] = useState<Encodes>(Encodes.gb2312)
  const [operateState, setOperateState] = useState(OperateState.idle)
  const [operatingSteps, setOperatingSteps] = useState("")
  const [downloadData, setDownloadData] = useState("")

  const menu = useRef(
    <Menu>
      <Menu.Item key={Encodes.gb2312}>
        <span onClick={() => setEncode(Encodes.gb2312)}>
          {Encodes.gb2312.toUpperCase()}
        </span>
      </Menu.Item>
      <Menu.Item key={Encodes.utf8}>
        <span onClick={() => setEncode(Encodes.utf8)}>
          {Encodes.utf8.toUpperCase()}
        </span>
      </Menu.Item>
    </Menu>
  )

  const changeFileName = useCallback<ChangeEventHandler<HTMLInputElement>>((str) => {
    setFileName(str.target.value)
  }, [])
  const map2Index = useMemo<Record<string, number>>(() => ({ "品种": 0, "中文名": 1, "净持量": 2, "对冲量": 3, "结算价": 4, "每手乘数": 5, "保证金比例": 6, "净持仓市值": 7, "市值": 8, "对冲保证金": 9 }), [])
  // 保存文件使用的顺序
  const [items, setItems] = useState(["品种", "中文名", "净持量", "对冲量", "结算价", "每手乘数", "保证金比例", "净持仓市值", "市值", "对冲保证金"])
  const handleFiles = useCallback(async () => {
    if (!fileName) {
      setOperatingSteps("文件名不能为空")
      return
    }
    if (!selectFileList.length) {
      setOperatingSteps("未选择文件")
      return
    }
    setOperateState(OperateState.operate)
    const list: List = []
    const lost: string[] = []; // 缺失品种
    try {
      for (let i = 0; i < selectFileList.length; i++) {
        const file = selectFileList[i]
        setOperatingSteps(`读取csv文件：${file.name}`)
        const page = await readCSV(file as any)
        list.push(...page)
      }
      console.log(list);
      setOperatingSteps(`读取xls文件：${addonFile[0].name}`)
      const xls = await readXLSX(addonFile[0] as any)
      setOperatingSteps("合并数据")
      const union: Union = {}
      list.forEach(ele => {
        const key = ele.key
        if (union[key]) {
          union[key].vcl += ele.vcl
          union[key].czsz += ele.czsz
          if (ele.vcl > 0) {
            union[key].vcl_positive += ele.vcl
          } else {
            union[key].vcl_negative += ele.vcl
          }
        } else {
          union[key] = {
            vcl: ele.vcl,
            vcl_positive: ele.vcl > 0 ? ele.vcl : 0,
            vcl_negative: ele.vcl < 0 ? ele.vcl : 0,
            czsz: ele.czsz,
            name: names[key],
            jsj: xls[key] || undefined,
            mscs: mscs[key],
            bzj: bzj[key]
          }
        }
      })
      console.log(union);
      // 根据输出对输入信息缺失的情况做一次补全操作
      totalLists.forEach(key => {
        if (!union[key]) {
          lost.push(names[key])
          union[key] = { vcl: 0, czsz: 0, vcl_positive: 0, vcl_negative: 0, name: names[key], jsj: xls[key] || undefined, mscs: mscs[key], bzj: bzj[key] }
        }
      })
      const rows: (string | number)[][] = [["品种", "", "净持量", "对冲量", "结算价", "每手乘数", "保证金比例", "净持仓市值", "市值", "对冲保证金"]]
      // 总计
      let blockVclCount = 0;
      let blockVclMinCount = 0;
      let blockCzszCount = 0;
      let blockJccszCount = 0
      let blockDcbzjCount = 0;
      subtotalLists.forEach(block => {
        // 小计
        let blockVcl = 0;
        let blockCzsz = 0;
        let blockJccsz = 0;
        let blockVclMin = 0;
        let blockDcbzj = 0;
        block.forEach(key => {
          const item = union[key]
          const vclMin = Math.min(item.vcl_positive, Math.abs(item.vcl_negative))
          const dcbzj = parseFloat(vclMin * (item.jsj || 0) * item.mscs * parseFloat(item.bzj) / 100 + "")
          blockVcl += item.vcl;
          blockCzsz += item.czsz;
          blockVclMin += vclMin;
          blockDcbzj += dcbzj;

          // 净持仓市值
          const jccsz = item.jsj ? item.vcl * item.jsj * item.mscs : undefined
          blockJccsz += (jccsz || 0)
          rows.push([key, item.name, addNumSplit(item.vcl), addNumSplit(vclMin), addNumSplit(item.jsj), item.mscs, item.bzj, jccsz || 0, addNumSplit(item.czsz), addNumSplit(dcbzj)])
        })
        rows.push(["", "小计", addNumSplit(blockVcl), addNumSplit(blockVclMin), "", "", "", addNumSplit(blockJccsz), addNumSplit(blockCzsz), addNumSplit(blockDcbzj)])
        rows.push(["", "", "", "", "", "", "", "", "", ""])
        rows.push(["品种", "", "净持量", "对冲量", "结算价", "每手乘数", "保证金比例", "净持仓市值", "市值", "对冲保证金"])
        blockVclCount += blockVcl
        blockCzszCount += blockCzsz
        blockVclMinCount += blockVclMin
        blockJccszCount += blockJccsz
        blockDcbzjCount += blockDcbzj
      })
      rows.push(["", "总计", addNumSplit(blockVclCount), addNumSplit(blockVclMinCount), "", "", "", addNumSplit(blockJccszCount), addNumSplit(blockCzszCount), addNumSplit(blockDcbzjCount)])
      setOperatingSteps("生成完成" + (lost.length ? `，缺失品种：${lost.join(",")}` : ""))

      // 重新生成顺序
      const sortedIndex = items.map(name => map2Index[name])

      setDownloadData(`data:text/csv;charset=gb2312,\ufeff${encodeURIComponent(rows.map(row => sortedIndex.map(idx => row[idx]).join(",")).join("\n"))}`)
      setOperateState(OperateState.done)

      console.log(window.ipcRenderer);
    } catch (error) {
      console.log(error);
      setOperatingSteps(`错误：${error}`)
    }
  }, [fileName, selectFileList, addonFile, items, map2Index])
  const handleSelectFileList = useCallback<(info: UploadChangeParam) => any>(info => {
    console.log(info);
    setSelectFileList(old => {
      if (old.length > info.fileList.length) {
        // 删除
        return info.fileList
      } else if (old.findIndex(file => file.name === info.file.name) === -1) {
        // 添加新项
        setOperateState(OperateState.idle)
        return [...old, info.file]
      }
      return old
    })
  }, [])

  const handleAddonFile = useCallback<(info: UploadChangeParam) => any>((info) => {
    setAddonFile(old => {
      if (old.length > info.fileList.length) {
        // 删除
        return info.fileList
      } else if (old[0]?.name !== info.file.name) {
        return [info.file]
      }
      return old
    })
  }, [])

  return <Container>
    <Helmet>
      <title>头寸统计</title>
    </Helmet>
    <Upload disabled={operateState === OperateState.operate} fileList={selectFileList} onChange={handleSelectFileList} accept=".csv" beforeUpload={() => false} multiple>
      <Button disabled={operateState === OperateState.operate} type="primary">选择处理文件</Button>
    </Upload>
    <br />
    <Upload disabled={operateState === OperateState.operate} fileList={addonFile} onChange={handleAddonFile} accept=".xls,.xlsx" beforeUpload={() => false}>
      <Button disabled={operateState === OperateState.operate} type="primary">选择结算价文件</Button>
    </Upload>
    <Divider></Divider>
    <Draggable items={items} onChange={setItems} />
    <FileMsgWrapper>
      <Input addonBefore="输出文件名" addonAfter=".csv" value={fileName} onChange={changeFileName} />
      <Dropdown overlay={menu.current}>
        <Button className="encode">{encode.toUpperCase()}</Button>
      </Dropdown>
    </FileMsgWrapper>
    <Button type="primary" loading={operateState === OperateState.operate} disabled={operateState === OperateState.operate} onClick={handleFiles}>
      {operateState === OperateState.operate ? "处理中" : "读取并计算"}
    </Button>
    <Button disabled={!(downloadData && fileName)} type="link" href={downloadData} download={`${fileName}.csv`}>下载</Button>
    <OperateMsg>{operatingSteps}</OperateMsg>
  </Container>
}

const OperateMsg = styled.span`
  color: #999;
`

const Container = styled.div`
  padding: 15px;
  .ant-upload-list.ant-upload-list-text {
    display: flex;
    flex-wrap: wrap;
  }
`

const FileMsgWrapper = styled.div`
  display: flex;
  margin-bottom: 15px;
  .ant-input-group-wrapper {
    margin-right: 15px;
    flex: none;
    width: 300px;
  }
  .encode {
    width: 100px;
    flex: none;
  }
`

export default Main
